﻿Imports Telerik.Web.UI
Imports Telerik.Web.UI.Widgets
Imports System.Web
Imports System

Imports DotNetNuke.Common.Globals
Imports DotNetNuke
Imports DotNetNuke.Entities.Portals
Imports DotNetNuke.Security
Imports System.IO

Imports System.Collections.Generic
Imports Bring2mind.DNN.Modules.DMX.Common

Imports Bring2mind.DNN.Modules.DMX.Business
Imports Bring2mind.DNN.Modules.DMX.Security.Permissions
Imports Bring2mind.DNN.Modules.DMX.Security
Imports DotNetNuke.Common.Utilities

Namespace Bring2mind.DNN.Modules.DMX.RadEditorContentProvider
 Public Class ContentProvider
  Inherits FileSystemContentProvider

#Region " Private Members "

  Private _itemHandlerPath As String

  Private ReadOnly Property ItemHandlerPath() As String
   Get
    Return _itemHandlerPath
   End Get
  End Property

  Private Portalsettings As PortalSettings = Nothing

  Private ReadOnly Property PortalId() As Integer
   Get
    Return Portalsettings.PortalId
   End Get
  End Property

  Private _userId As Integer = -2
  Private ReadOnly Property UserId() As Integer
   Get
    If _userId < -1 Then
     If Portalsettings.UserInfo.IsSuperUser Then
      _userId = Portalsettings.AdministratorId
     Else
      _userId = Portalsettings.UserId
     End If
    End If
    Return _userId
   End Get
  End Property

  Private _dmxPath As String
  Public Property DMXPath() As String
   Get
    Return _dmxPath
   End Get
   Set(ByVal value As String)
    _dmxPath = value
   End Set
  End Property

#End Region

#Region " Overrides "

  Public Sub New( _
      ByVal context As HttpContext, _
      ByVal searchPatterns As String(), _
      ByVal viewPaths As String(), _
      ByVal uploadPaths As String(), _
      ByVal deletePaths As String(), _
      ByVal selectedUrl As String, _
      ByVal selectedItemTag As String)


   MyBase.New( _
       context, _
       searchPatterns, _
       viewPaths, _
       uploadPaths, _
       deletePaths, _
       selectedUrl, _
       selectedItemTag _
   )

   Portalsettings = DotNetNuke.Entities.Portals.PortalController.GetCurrentPortalSettings

   DMXPath = viewPaths(0)

  End Sub


  Public Overrides Function ResolveRootDirectoryAsTree(ByVal path As String) As Telerik.Web.UI.Widgets.DirectoryItem


   'as this method is being called 5 times (!) for each initial load and then again for each ajax call that 
   'loads a given subtree, we need to store the reuslt in the cache
   If Not DataCache.GetCache("DMXRAD_CHILDDIRECTORIES_" & path) Is Nothing Then
    Return CType(DataCache.GetCache("DMXRAD_CHILDDIRECTORIES_" & path), Telerik.Web.UI.Widgets.DirectoryItem)
   End If

   Dim ParentFolder As EntryInfo = GetEntryFromPath(path)
   Dim folderPermission As PathPermissions = 0
   Dim childdirectories As DirectoryItem() = New DirectoryItem() {}

   If Not ParentFolder Is Nothing Then

    If ParentFolder.CanAdd Then
     folderPermission = PathPermissions.Read Or PathPermissions.Upload ' removed delete permission
    End If

    childdirectories = GetChildDirectories(ParentFolder, EndWithSlash(path))

   End If

   Dim returnValue As New DirectoryItem( _
       GetName(path), _
       GetDirectoryPath(path), _
       path, _
       String.Empty, _
       folderPermission, _
       New FileItem() {}, _
       childdirectories _
       )

   DataCache.SetCache("DMXRAD_CHILDDIRECTORIES_" & path, returnValue)

   Return returnValue

  End Function

  Public Overrides Function ResolveDirectory(ByVal path As String) As Telerik.Web.UI.Widgets.DirectoryItem

   Dim ParentFolder As EntryInfo = GetEntryFromPath(path)
   Dim folderPermission As PathPermissions = 0
   Dim childfiles As FileItem() = New FileItem() {}
   Dim childdirectories As DirectoryItem() = New DirectoryItem() {}

   If Not ParentFolder Is Nothing Then

    folderPermission = PathPermissions.Read
    childfiles = GetChildFiles(ParentFolder, path)
    childdirectories = GetChildDirectories(ParentFolder, path)

    If ParentFolder.CanAdd Then
     folderPermission = PathPermissions.Read Or PathPermissions.Upload ' removed delete permission
    End If

   End If

   For Each fileItem As FileItem In childfiles
    If String.Compare(fileItem.Extension, "jpg", True) = 0 Or _
        String.Compare(fileItem.Extension, "gif", True) = 0 Or _
        String.Compare(fileItem.Extension, "jpeg", True) = 0 Or _
        String.Compare(fileItem.Extension, "bmp", True) = 0 Or _
        String.Compare(fileItem.Extension, "png", True) = 0 Then
     fileItem.Attributes.Add("Thumb", "<img src=""" & fileItem.Url & """ width=""40"">")
    End If
   Next

   Return New DirectoryItem( _
       GetName(path), _
       EndWithSlash(GetDirectoryPath(path)), _
       String.Empty, _
       String.Empty, _
       folderPermission, _
       childfiles, _
       childdirectories _
       )

  End Function

  Public Overrides Function ResolveRootDirectoryAsList(ByVal path As String) As Telerik.Web.UI.Widgets.DirectoryItem()
   Return MyBase.ResolveRootDirectoryAsList(path)
  End Function

  Public Overrides ReadOnly Property CanCreateDirectory() As Boolean
   Get
    Return MyBase.CanCreateDirectory
   End Get
  End Property

  Public Overrides Function CreateDirectory(ByVal path As String, ByVal name As String) As String

   Try
    Dim objParent As EntryInfo = GetEntryFromPath(path)
    EntriesController.MakeCollection(PortalId, objParent.EntryId, name, New DMXUser(Portalsettings.UserInfo), False)
   Catch ex As Exception
    Return ex.Message
   End Try
   Return String.Empty

  End Function

  Public Overrides Function DeleteDirectory(ByVal path As String) As String

   Return "You can't delete folders."
   'Try
   ' Dim folder As New System.IO.DirectoryInfo(AbsolutePath(path))
   ' DeleteFolder(Portalsettings.PortalId, folder, CleanPath(path))
   'Catch ex As Exception
   ' Return "You can only delete folders when all files in the folder have been deleted!"
   'End Try
   'Return String.Empty

  End Function

  Public Overrides Function DeleteFile(ByVal path As String) As String
   'DotNetNuke.Common.Utilities.FileSystemUtils.DeleteFile(AbsolutePath(path), Portalsettings, True)
   Dim Entry As EntryInfo = GetEntryFromPath(path)
   If Entry IsNot Nothing Then
    If Entry.CanEdit Then
     Entry.Delete(True)
    Else
     Return "Not Allowed"
    End If
   Else
    Return "Not Found"
   End If
   Return String.Empty
  End Function

  Public Overrides Function Equals(ByVal obj As Object) As Boolean
   Return MyBase.Equals(obj)
  End Function

  Public Overrides Function GetFile(ByVal url As String) As System.IO.Stream
   Return MyBase.GetFile(url.Replace("//", "/"))
  End Function

  Public Overrides Function GetFileName(ByVal url As String) As String
   Return MyBase.GetFileName(url.Replace("//", "/"))
  End Function

  Public Overrides Function GetHashCode() As Integer
   Return MyBase.GetHashCode()
  End Function

  Public Overrides Function GetPath(ByVal url As String) As String
   Return MyBase.GetPath(url.Replace("//", "/"))
  End Function

  Protected Overrides Function IsValid(ByVal directory As System.IO.DirectoryInfo) As Boolean
   Return MyBase.IsValid(directory)
  End Function

  Protected Overrides Function IsValid(ByVal file As System.IO.FileInfo) As Boolean
   Return MyBase.IsValid(file)
  End Function

  Public Overrides Function MoveDirectory(ByVal path As String, ByVal newPath As String) As String

   Dim entryToMove As EntryInfo = GetEntryFromPath(path)
   If entryToMove Is Nothing Then
    Return "Did not find source folder"
   End If
   Dim TargetFolder As EntryInfo = GetEntryFromPath(newPath)
   If TargetFolder Is Nothing Then
    Return "Did not find target folder"
   End If
   Return EntriesController.MoveEntry(PortalId, entryToMove.EntryId, UserId, TargetFolder.EntryId)

  End Function

  Public Overrides Function MoveFile(ByVal path As String, ByVal newPath As String) As String

   Dim entryToMove As EntryInfo = GetEntryFromPath(path)
   If entryToMove Is Nothing Then
    Return "Did not find source file"
   End If
   Dim TargetFolder As EntryInfo = GetEntryFromPath(newPath)
   If TargetFolder Is Nothing Then
    Return "Did not find target folder"
   End If
   Return EntriesController.MoveEntry(PortalId, entryToMove.EntryId, UserId, TargetFolder.EntryId)

  End Function

  Public Overrides Function StoreBitmap(ByVal bitmap As System.Drawing.Bitmap, ByVal url As String, ByVal format As System.Drawing.Imaging.ImageFormat) As String
   ' todo: not sure what should happen here
   Return MyBase.StoreBitmap(bitmap, url, format)
  End Function

  Public Overrides Function StoreFile(ByVal file As Telerik.Web.UI.UploadedFile, ByVal path As String, ByVal name As String, ByVal ParamArray arguments() As String) As String

   AddFile(Portalsettings.PortalId, file.InputStream, AbsolutePath(path & file.GetName), file.ContentType, file.ContentLength, path, True, True, False)

   Return String.Empty

  End Function

  Public Overrides Function ToString() As String
   Return MyBase.ToString()
  End Function

#End Region

#Region " Private Listing Methods "

  Private Function GetChildDirectories(ByVal objParent As EntryInfo, ByVal path As String) As DirectoryItem()

   If Not DataCache.GetCache("DMXRAD_CHILDDIRECTORIES_" & objParent.EntryId.ToString) Is Nothing Then
    Return CType(DataCache.GetCache("DMXRAD_CHILDDIRECTORIES_" & objParent.EntryId.ToString), DirectoryItem())
   End If

   Dim directories As New List(Of DirectoryItem)

   Dim Folderlist As List(Of EntryInfo) = EntriesController.GetSubCollections(PortalId, objParent.EntryId, UserId, False, Threading.Thread.CurrentThread.CurrentCulture.Name)

   For Each objFolder As EntryInfo In Folderlist
    Dim fpath As String = objFolder.FullPath(False, Threading.Thread.CurrentThread.Name)
    directories.Add(New DirectoryItem(objFolder.Title, String.Empty, fpath, fpath, GetEntryPermissions(objFolder), GetChildFiles(objFolder, path), GetChildDirectories(objFolder, path)))
   Next

   If directories.Count > 0 Then
    DataCache.SetCache("DMXRAD_CHILDDIRECTORIES_" & objParent.EntryId.ToString, directories.ToArray)
    Return directories.ToArray
   End If

   DataCache.SetCache("DMXRAD_CHILDDIRECTORIES_" & objParent.EntryId.ToString, New DirectoryItem() {})
   Return New DirectoryItem() {}

  End Function

  Private Function GetChildFiles(ByVal objParent As EntryInfo, ByVal path As String) As FileItem()

   If Not DataCache.GetCache("DMXRAD_CHILDFILES_" & objParent.EntryId.ToString) Is Nothing Then
    Return CType(DataCache.GetCache("DMXRAD_CHILDFILES_" & objParent.EntryId.ToString), FileItem())
   End If

   Dim files As New ArrayList()
   Dim FileList As List(Of EntryInfo) = EntriesController.GetCollectionContents(PortalId, objParent.EntryId, UserId, False, Threading.Thread.CurrentThread.Name, True, True, False)

   Dim folderPermission As PathPermissions = GetEntryPermissions(objParent)

   For Each objFile As EntryInfo In FileList

    If objFile.IsFile Then

     Dim filePermission As PathPermissions = PathPermissions.Read
     If objFile.CanEdit Then
      filePermission = filePermission Or PathPermissions.Delete
     End If
     If SearchPatterns.Length = 1 Then
      If SearchPatterns(0) = "*.*" Then
       files.Add(New FileItem(objFile.Title & IO.Path.GetExtension(objFile.OriginalFileName), IO.Path.GetExtension(objFile.OriginalFileName), Convert.ToDouble(objFile.FileSize), CombinePath(path, objFile.DavName(False)), GetDownloadUrl(objFile.EntryId), objFile.EntryId, folderPermission))
      End If
     ElseIf (SearchPatterns.Length > 0) Then
      For Each strExtension As String In SearchPatterns
       If strExtension = "*.*" Then
        files.Add(New FileItem(objFile.Title & IO.Path.GetExtension(objFile.OriginalFileName), IO.Path.GetExtension(objFile.OriginalFileName), Convert.ToDouble(objFile.FileSize), CombinePath(path, objFile.DavName(False)), GetDownloadUrl(objFile.EntryId), objFile.EntryId, folderPermission))
       Else
        If strExtension.ToLower.Replace(".", "").Replace("*", "") = IO.Path.GetExtension(objFile.OriginalFileName).ToLower.Replace(".", "") Then
         files.Add(New FileItem(objFile.Title & IO.Path.GetExtension(objFile.OriginalFileName), IO.Path.GetExtension(objFile.OriginalFileName), Convert.ToDouble(objFile.FileSize), CombinePath(path, objFile.DavName(False)), GetDownloadUrl(objFile.EntryId), objFile.EntryId, folderPermission))
        End If
       End If
      Next
     Else
      files.Add(New FileItem(objFile.Title & IO.Path.GetExtension(objFile.OriginalFileName), IO.Path.GetExtension(objFile.OriginalFileName), Convert.ToDouble(objFile.FileSize), CombinePath(path, objFile.DavName(False)), GetDownloadUrl(objFile.EntryId), objFile.EntryId, folderPermission))
     End If

    End If


   Next

   If FileList.Count > 0 Then
    DataCache.SetCache("DMXRAD_CHILDFILES_" & objParent.EntryId.ToString, DirectCast(files.ToArray(GetType(FileItem)), FileItem()))
    Return DirectCast(files.ToArray(GetType(FileItem)), FileItem())
   End If

   DataCache.SetCache("DMXRAD_CHILDFILES_" & objParent.EntryId.ToString, New FileItem() {})
   Return New FileItem() {}

  End Function

#End Region

#Region "Private Helper Methods"

  Private Function GetDownloadUrl(ByVal EntryId As Integer) As String
   Return ResolveUrl("~/Desktopmodules/Bring2Mind/DMX/Download.aspx?EntryId=" & EntryId & "&PortalId=" & Portalsettings.PortalId.ToString)
  End Function

  Private Function GetEntryFromPath(ByVal path As String) As EntryInfo

   Dim requestedEntry As EntryInfo = Nothing
   Dim cleanedPath As String = CleanPath(path)
   If String.IsNullOrEmpty(cleanedPath) OrElse cleanedPath = "/" Then
    requestedEntry = EntriesController.GetRootEntry(PortalId)
   Else
    requestedEntry = EntriesController.GetEntryByDavPath(PortalId, UserId, glbWebdavHandler & "/" & cleanedPath)
   End If
   Return requestedEntry

  End Function

  Private Function GetEntryPermissions(ByVal objEntry As EntryInfo) As PathPermissions
   Dim res As PathPermissions = PathPermissions.Read ' by definition or else we wouldn't see it
   If objEntry.CanAdd Then
    res = res Or PathPermissions.Upload
   End If
   If objEntry.CanEdit Then
    res = res Or PathPermissions.Delete
   End If
   Return res
  End Function

  Private Function AddFile(ByVal PortalId As Integer, ByVal inStream As Stream, ByVal fileName As String, ByVal contentType As String, ByVal length As Long, ByVal folderName As String, ByVal closeInputStream As Boolean, ByVal clearCache As Boolean, ByVal synchronize As Boolean) As String

   Dim objFolder As EntryInfo = GetEntryFromPath(folderName)
   Dim sourceFileName As String = System.IO.Path.GetFileName(fileName).Replace(glbProtectedExtension, "")
   Dim retValue As String = ""

   retValue += CheckValidFileName(fileName)
   If retValue.Length > 0 Then
    Return retValue
   End If

   Try
    EntriesController.SimplifiedUpload(PortalId, objFolder.EntryId, inStream, sourceFileName, IO.Path.GetFileNameWithoutExtension(sourceFileName), Portalsettings.UserInfo, False)
   Catch ex As Exception
    retValue = ex.Message
   End Try

   Return retValue

  End Function

  Private Shared Function CheckValidFileName(ByVal strFileName As String) As String

   Dim retValue As String = String.Empty
   If strFileName.IndexOf("'") > -1 Then
    retValue = "InvalidFileName"
   End If

   'Return
   Return retValue

  End Function

  Private Function GetDirectoryPath(ByVal path As String) As String
   Return path.Substring(0, path.LastIndexOf("/"c) + 1)
  End Function

  Private Function IsChildOf(ByVal parentPath As String, ByVal childPath As String) As Boolean
   Return childPath.StartsWith(parentPath)
  End Function

  Private Function EndWithSlash(ByVal path As String) As String
   If Not path.EndsWith("/") Then
    Return path & "/"
   End If
   Return path
  End Function

  Private Function CombinePath(ByVal path1 As String, ByVal path2 As String) As String
   If path1.EndsWith("/") Then
    Return String.Format("{0}{1}", path1, path2)
   End If
   If path1.EndsWith("\") Then
    path1 = path1.Substring(0, path1.Length - 1)
   End If
   Return String.Format("{0}/{1}", path1, path2)
  End Function

  Private Function GetItemUrl(ByVal virtualItemPath As String) As String
   Return String.Format("{0}?path={1}", ItemHandlerPath, virtualItemPath)
  End Function

  Private Function ExtractPath(ByVal itemUrl As String) As String
   If itemUrl Is Nothing Then
    Return String.Empty
   End If
   If itemUrl.StartsWith(_itemHandlerPath) Then
    Return itemUrl.Substring(GetItemUrl(String.Empty).Length)
   End If
   Return itemUrl
  End Function

  Private Function GetName(ByVal Path As String) As String
   Dim strPath As String = String.Empty
   If Path Is Nothing Then
    Return String.Empty
   End If
   If EndWithSlash(Path) = EndWithSlash(Portalsettings.HomeDirectory) Then
    Return "DMX"
   End If
   If Path.Contains("/") Then
    strPath = Path.Substring(Path.LastIndexOf("/") + 1)
   End If
   If strPath = String.Empty Then
    Return "DMX"
   End If
   Return strPath
  End Function

  Private Function IsExtensionAllowed(ByVal extension As String) As Boolean
   Return Array.IndexOf(SearchPatterns, "*.*") >= 0 OrElse Array.IndexOf(SearchPatterns, "*" & extension.ToLower()) >= 0
  End Function

  Private Function RemoveLastSlash(ByVal path As String) As String
   If path.EndsWith("/") Then
    Return path.Substring(0, path.Length - 1)
   End If
   Return path
  End Function

  Private Function CleanPath(ByVal path As String) As String
   If String.IsNullOrEmpty(DMXPath) Then Return path
   If path.StartsWith(DMXPath) Then
    path = Mid(path, DMXPath.Length + 1)
   End If
   Return path
  End Function


  Private Function AbsolutePath(ByVal path As String) As String
   path = CleanPath(path)
   Dim absPath As String = Portalsettings.HomeDirectoryMapPath
   absPath += path
   Return absPath
  End Function

#End Region

 End Class
End Namespace
